package com.atguigu.gmall.order.service.impl;

import com.alibaba.fastjson.JSON;
import com.atguigu.gmall.common.constant.MqConst;
import com.atguigu.gmall.common.service.RabbitService;
import com.atguigu.gmall.common.util.HttpClientUtil;
import com.atguigu.gmall.model.enums.OrderStatus;
import com.atguigu.gmall.model.enums.ProcessStatus;
import com.atguigu.gmall.model.order.OrderDetail;
import com.atguigu.gmall.model.order.OrderInfo;
import com.atguigu.gmall.order.mapper.OrderDetailMapper;
import com.atguigu.gmall.order.mapper.OrderInfoMapper;
import com.atguigu.gmall.order.service.OrderService;
import com.atguigu.gmall.product.client.ProductFeignClient;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.util.*;

/**
 * @author mqx
 * @date 2020-10-22 11:53:09
 */
@Service
public class OrderServiceImpl extends ServiceImpl<OrderInfoMapper,OrderInfo> implements OrderService {

    @Autowired
    private OrderInfoMapper orderInfoMapper;

    @Autowired
    private OrderDetailMapper orderDetailMapper;

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private RabbitService rabbitService;

    @Value("${ware.url}")
    private String WARE_URL;

    @Override
    @Transactional
    public Long saveOrderInfo(OrderInfo orderInfo) {
        /*
            保存应该有两张表：
            orderInfo ,orderDetail;
            传递传递的数据保存，如果表中有部分字段，前台并没有传递，则需要我们手动填写。
         */
        //  总金额，订单状态，【userId】,第三方交易编号，订单的主体描述，创建时间，过期时间，进度状态
        //  前提是OrderInfo 中必须有订单明细。
        orderInfo.sumTotalAmount();
        orderInfo.setOrderStatus(OrderStatus.UNPAID.name());
        // 按照某个规则进行随机生产，保证不能重复。
        String outTradeNo = "ATGUIGU" + System.currentTimeMillis() + "" + new Random().nextInt(1000);
        orderInfo.setOutTradeNo(outTradeNo);

        //  放入字符串， 真正环境{可以给商品的名称}
        List<OrderDetail> orderDetailList = orderInfo.getOrderDetailList();
        StringBuilder sb = new StringBuilder();
//        for (OrderDetail orderDetail : orderDetailList) {
//             sb.append(orderDetail.getSkuName());
//        }
//        //  限制：长度 不能超过两百。
//        if (sb.length()>200){
//            //  拼接
//            orderInfo.setTradeBody(sb.substring(0,200));
//        }else {
//            orderInfo.setTradeBody(sb.toString());
//        }
          orderInfo.setTradeBody("冬天买大衣.");

          orderInfo.setCreateTime(new Date());
          //    过期时间为1天
        Calendar calendar = Calendar.getInstance();
        //  表示在当前系统时间+1天
        calendar.add(Calendar.DATE,1);
        orderInfo.setExpireTime(calendar.getTime());

        orderInfo.setProcessStatus(ProcessStatus.UNPAID.name());
        //  订单主表保存
        orderInfoMapper.insert(orderInfo);
        //  保存订单明细
        //  orderInfo.getOrderDetailList(); 从前台页面获取到购物车中的商品集合。
        List<OrderDetail> orderDetailLists = orderInfo.getOrderDetailList();
        for (OrderDetail orderDetail : orderDetailLists) {
            //  OrderDetail orderDetail = new OrderDetail();
            orderDetail.setOrderId(orderInfo.getId());
            //  保存：
            orderDetailMapper.insert(orderDetail);
        }

        //  发送消息
        //  发送的内容：为订单Id
        rabbitService.sendDelayMessage(MqConst.EXCHANGE_DIRECT_ORDER_CANCEL,MqConst.ROUTING_ORDER_CANCEL,orderInfo.getId(),MqConst.DELAY_TIME);
        //  返回订单Id
        return orderInfo.getId();
    }

    @Override
    public String getTradeNo(String userId) {
        //  制作一个流水号
        String tradeNo = UUID.randomUUID().toString();
        //  将这个流水号存储缓存
        String tradeNoKey = "tradeNo:"+userId;
        //  暂时不设置过期时间
        redisTemplate.opsForValue().set(tradeNoKey,tradeNo);
        //  返回流水号
        return tradeNo;
    }

    @Override
    public Boolean checkTradeCode(String tradeNo, String userId) {
        //  将这个流水号存储缓存
        String tradeNoKey = "tradeNo:"+userId;
        //  获取缓存数据
        String tradeNoCode = (String) redisTemplate.opsForValue().get(tradeNoKey);
        //  返回比较结果
        return tradeNo.equals(tradeNoCode);
    }

    @Override
    public void delTradeNo(String userId) {
        //  将这个流水号存储缓存
        String tradeNoKey = "tradeNo:"+userId;
        //  删除
        redisTemplate.delete(tradeNoKey);
    }

    @Override
    public boolean checkStock(Long skuId, Integer skuNum) {

        //  查询库存：远程调用ware-manage
        //  在这不能使用feign！ware-manage 单独spring boot 项目！
        //  远程工具类调用
        //  WARE_URL = http://localhost:9001
        String flag = HttpClientUtil.doGet(WARE_URL + "/hasStock?skuId=" + skuId + "&num=" + skuNum);
        //  flag = 0 表示没有足够的库存。
        //  如果是1 表示有足够的库存，否则没有！
        return "1".equals(flag);
    }

    @Override
    public void execExpiredOrder(Long orderId) {
        // update order_info set OrderStatus = ? and ProcessStatus = ? where id = orderId;
//        OrderInfo orderInfo = new OrderInfo();
//        orderInfo.setId(orderId);
//        //  从进程状态中能够获取到订单状态！
//        orderInfo.setOrderStatus(ProcessStatus.CLOSED.getOrderStatus().name());
//        orderInfo.setProcessStatus(ProcessStatus.CLOSED.name());
//        //  更新了！
//        orderInfoMapper.updateById(orderInfo);

        updateOrderStatus(orderId, ProcessStatus.CLOSED);

        //  发送消息关闭交易记录
        rabbitService.sendMessage(MqConst.EXCHANGE_DIRECT_PAYMENT_CLOSE,MqConst.ROUTING_PAYMENT_CLOSE,orderId);

    }

    public void updateOrderStatus(Long orderId, ProcessStatus processStatus) {
        //  声明一个对象。
        OrderInfo orderInfo = new OrderInfo();
        orderInfo.setId(orderId);
        //  从进程状态中能够获取到订单状态！
        orderInfo.setOrderStatus(processStatus.getOrderStatus().name());
        orderInfo.setProcessStatus(processStatus.name());
        //  更新了！
        orderInfoMapper.updateById(orderInfo);
    }

    @Override
    public OrderInfo getOrderInfo(Long orderId) {
        //  不但查询orderInfo ,还需要查询一个订单明细。
        OrderInfo orderInfo = orderInfoMapper.selectById(orderId);
        //  不为空时查询订单明细
        if (orderInfo!=null){
            //  查询订单明细
            List<OrderDetail> orderDetailList = orderDetailMapper.selectList(new QueryWrapper<OrderDetail>().eq("order_id", orderId));
            orderInfo.setOrderDetailList(orderDetailList);
        }

        return orderInfo;
    }

    @Override
    public void sendOrderStatus(Long orderId) {
        //  更改订单状态！
        updateOrderStatus(orderId,ProcessStatus.NOTIFIED_WARE);
        //  因为Json 字符串是由orderInfo 中部分字段组成 ，我们将这个部分字段制作成一个Map
        //  最好将map 转化为Json 字符串即可！
        String wareJson =  initWareOrder(orderId);
        //  发送消息
        rabbitService.sendMessage(MqConst.EXCHANGE_DIRECT_WARE_STOCK,MqConst.ROUTING_WARE_STOCK,wareJson);


    }
    //  将字符串返回
    private String initWareOrder(Long orderId) {
        //  获取订单OrderInfo
        OrderInfo orderInfo = getOrderInfo(orderId);
        Map map = initWareOrder(orderInfo);
        return JSON.toJSONString(map);
    }

    //  因为Json 字符串是由orderInfo 中部分字段组成 ，我们将这个部分字段制作成一个Map
    public Map initWareOrder(OrderInfo orderInfo) {
        HashMap<String, Object> map = new HashMap<>();
        map.put("orderId", orderInfo.getId());
        map.put("consignee", orderInfo.getConsignee());
        map.put("consigneeTel", orderInfo.getConsigneeTel());
        map.put("orderComment", orderInfo.getOrderComment());
        map.put("orderBody", orderInfo.getTradeBody());
        map.put("deliveryAddress", orderInfo.getDeliveryAddress());
        map.put("paymentWay", "2");
        map.put("wareId", orderInfo.getWareId());// 仓库Id ，减库存拆单时需要使用！
        //  details:[{skuId:101,skuNum:1,skuName:’小米手64G’},{skuId:201,skuNum:1,skuName:’索尼耳机’}]
        //  获取订单明细
        List<Map> maps = new ArrayList<>();
        List<OrderDetail> orderDetailList = orderInfo.getOrderDetailList();
        if (!CollectionUtils.isEmpty(orderDetailList)){
            //  获取订单明细中的数据 skuId:101,skuNum:1,skuName:’小米手64G’
            for (OrderDetail orderDetail : orderDetailList) {
                HashMap<String, Object> detailMap = new HashMap<>();

                detailMap.put("skuId",orderDetail.getSkuId());
                detailMap.put("skuNum",orderDetail.getSkuNum());
                detailMap.put("skuName",orderDetail.getSkuName());
                maps.add(detailMap);
            }
        }
        //  map.put("details",JSON.toJSONString(maps));
        map.put("details",maps);
        return map;
    }

    @Override
    @Transactional
    public List<OrderInfo> orderSplit(Long orderId, String wareSkuMap) {
        /*
        1.  先获取到原始订单
        2.  需要将wareSkuMap 字符串转化为为我们能操作的java 对象
            [{"wareId":"1","skuIds":["2","10"]},{"wareId":"2","skuIds":["3"]}]
        3.  需要创建一个新的子订单
          orderInfo:  1   admin   100     spilt                 | orderDetail :  2，10，3
          orderInfo:  2   admin   80      paid      1           | orderDetail :  2，10
          orderInfo:  3   admin   20      paid      1           | orderDetail :  3
        4.  给子订单进行赋值
        5.  保存子订单,将新的子订单添加到子订单集合中
        6.  修改原始订单的状态
         */
        List<OrderInfo> subOrderInfoList = new ArrayList<>();
        //  原始订单
        OrderInfo orderInfoOrigin = getOrderInfo(orderId);
        //  转化对象wareSkuMap
        List<Map> mapList = JSON.parseArray(wareSkuMap, Map.class);
        if (!CollectionUtils.isEmpty(mapList)){
            //  循环遍历
            for (Map map : mapList) {
                //  获取仓库id
                String wareId = (String) map.get("wareId");
                //  获取仓库Id 对应的商品Id
                List<String> skuIdList = (List<String>) map.get("skuIds");
                //  创建子订单
                OrderInfo subOrderInfo = new OrderInfo();
                //  属性拷贝
                BeanUtils.copyProperties(orderInfoOrigin,subOrderInfo);
                //  设置部分字段数据
                subOrderInfo.setId(null);

                //  价格：根据订单明细中的商品计算的！
                //  计算子订单的价格，所以我们需要知道子订单明细！
                //  声明一个子订单明细集合
                List<OrderDetail> orderDetails = new ArrayList<>();
                List<OrderDetail> orderDetailList = orderInfoOrigin.getOrderDetailList();
                if (!CollectionUtils.isEmpty(orderDetailList)){
                    //  循环遍历
                    for (OrderDetail orderDetail : orderDetailList) {
                        //  循环仓库Id 对应的商品Id skuId
                        for (String skuId : skuIdList) {
                            //  判断是否有相同的skuId
//                            if (orderDetail.getSkuId().compareTo(Long.parseLong(skuId))!=0){
//                            }
                            if (orderDetail.getSkuId().intValue()==Long.parseLong(skuId)){
                                orderDetails.add(orderDetail);
                            }
                        }
                    }
                }
                //  子订单明细放入子订单
                subOrderInfo.setOrderDetailList(orderDetails);
                subOrderInfo.sumTotalAmount();
                //  赋值父Id
                subOrderInfo.setParentOrderId(orderId);
                //  赋值仓库Id
                subOrderInfo.setWareId(wareId);
                //  保存子订单
                saveOrderInfo(subOrderInfo);
                //  将新的子订单添加到子订单集合中
                subOrderInfoList.add(subOrderInfo);
            }
        }
        //  更新原始订单状态
        this.updateOrderStatus(orderId,ProcessStatus.SPLIT);

        return subOrderInfoList;
    }

    @Override
    public void execExpiredOrder(Long orderId, String flag) {
        //  关闭订单的！
        updateOrderStatus(orderId, ProcessStatus.CLOSED);
        //  判断
        if ("2".equals(flag)){
            //  发送消息关闭交易记录
            rabbitService.sendMessage(MqConst.EXCHANGE_DIRECT_PAYMENT_CLOSE,MqConst.ROUTING_PAYMENT_CLOSE,orderId);
        }


    }


}
